import {Injectable} from '@angular/core'
import {Piece} from '../models/piece'
import {BattleState, EventType, PlayerColor} from '../models/types'
import {Board} from '../models/board'
import {Machine} from '../models/machine'
import {Player} from '../models/player'

@Injectable({
  providedIn: 'root'
})
export class BattleService {
  private battleState: BattleState = 'NotStarted'
  private board = new Board()
  private boardPlayer: Player = new Player('Blue')
  ai = new Machine()

  constructor() {
    this.board.$boardEvent.subscribe((e: { type: EventType, player: Player }) => {
      if (!e || !e.player) return
      this.boardPlayer = e.player
      if (e.type === 'Finished') {
        this.setWon()
      } else if (e.type === 'Starting') {
        this.start()
      } else if (this.ai.canMove(e.player.color)) {
        this.aiMove(e.type)
      }
    })
    this.ai.setColor('Red')
    this.ai.enabled = true
  }

  get currentPlayer() {
    return this.boardPlayer
  }

  get pieces() {
    return this.board.pieces
  }

  get state(): BattleState {
    return this.battleState
  }

  getPlayer(color: PlayerColor) {
    return color === 'Red' ? this.board.playerRed : this.board.playerBlue
  }

  getPlayerPiecesCount(color: PlayerColor) {
    return this.board.pieces.reduce((count, row) => count + row.filter(p => p.color === color).length, 0)
  }

  isRunning() {
    return ['Started', 'Preparing'].includes(this.battleState)
  }

  prepare() {
    if (this.isRunning() && !window.confirm('游戏已经开始，确定重新开始吗？')) {
      return
    }
    this.ai.setPieces(this.board.pieces)
    this.battleState = 'Preparing'
    this.board.reset()
  }

  start() {
    this.battleState = 'Started'
    this.board.start()
  }

  reset() {
    this.battleState = 'NotStarted'
    this.board.reset()
  }

  move(piece: Piece) {
    switch (piece.state) {
      case 'Unactivated': // drop a piece
        this.board.active(piece)
        break
      case 'Marking': // ready to mark
        this.board.mark(piece)
        break
      case 'Deleting': // ready to delete
        this.board.kill(piece)
        break
      case 'Activated': // ready to move
        this.board.moveOut(piece)
        break
      case 'MovingIn': // finish moving
        this.board.moveIn(piece)
        break
      case 'MovingOut': // cancel moving
        this.board.cancelMoveOut(piece)
        break
    }
  }

  private setWon() {
    this.battleState = 'Finished'
    this.currentPlayer.setWon()
  }

  private aiMove(type: EventType) {
    this.ai.act((p) => {
      this.move(p)
    }, type, this.state)
  }
}
